<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>串口管理终端</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: #f4f4f9;
        }
        .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            width: 80%;
            margin: auto;
        }
        .terminal {
            width: 100%;
            height: 300px;
            background-color: #000;
            color: #0f0;
            padding: 10px;
            border-radius: 8px;
            overflow-y: auto;
            margin-bottom: 20px;
            white-space: pre-wrap; /* 保持换行 */
        }
        .controls {
            display: flex;
            justify-content: space-between;
            width: 100%;
            margin-bottom: 20px;
        }
        .controls select, .controls input[type="text"], .controls button {
            padding: 10px;
            font-size: 16px;
            border-radius: 5px;
            border: 1px solid #ccc;
        }
        .controls button {
            background-color: #007bff;
            color: white;
            cursor: pointer;
        }
        .controls button:hover {
            background-color: #0056b3;
        }
        .status-indicator {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            margin-left: 10px;
            display: inline-block;
        }
        .status-on {
            background-color: green;
        }
        .status-off {
            background-color: red;
        }
        .udp-controls {
            display: flex;
            justify-content: space-between;
            width: 100%;
            margin-top: 20px;
        }
        .udp-controls select, .udp-controls input, .udp-controls button {
            padding: 10px;
            font-size: 16px;
            border-radius: 5px;
            border: 1px solid #ccc;
        }
        .udp-controls button {
            background-color: #28a745;
            color: white;
            cursor: pointer;
        }
        .udp-controls button:hover {
            background-color: #218838;
        }
        .udp-terminal {
            width: 100%;
            height: 100px;
            background-color: #000;
            color: #0f0;
            padding: 10px;
            border-radius: 8px;
            overflow-y: auto;
            margin-top: 20px;
            white-space: pre-wrap; /* 保持换行 */
        }
        .udp-status-indicator {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            margin-left: 10px;
            display: inline-block;
        }
        .udp-status-on {
            background-color: green;
        }
        .udp-status-off {
            background-color: red;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>串口管理终端</h1>
        <div class="controls">
            <select id="serial-ports">
                <option value="">选择串口设备</option>
            </select>
            <select id="baud-rate">
                <option value="9600">9600</option>
                <option value="19200">19200</option>
                <option value="38400">38400</option>
                <option value="57600">57600</option>
                <option value="115200">115200</option>
            </select>
            <input type="text" id="send-data" placeholder="输入要发送的数据" onkeydown="if(event.key === 'Enter') sendData()">
            <select id="append-newline">
                <option value="0">无符号</option>
                <option value="1">\r</option>
                <option value="2">\n</option>
                <option value="3">\r\n</option>
            </select>
            <button onclick="openSerialPort()">打开串口</button>
            <button onclick="closeSerialPort()">关闭串口</button>
            <button onclick="sendData()">发送</button>
            <button onclick="clearTerminal()">清空</button>
            <span id="serial-status" class="status-indicator status-off"></span>
        </div>
        <div class="terminal" id="terminal"></div>
        <div class="udp-controls">
            <input type="number" id="udp-port" placeholder="UDP端口">
            <select id="udp-serial-port">
                <option value="">选择串口设备</option>
            </select>
            <select id="udp-baud-rate">
                <option value="9600">9600</option>
                <option value="19200">19200</option>
                <option value="38400">38400</option>
                <option value="57600">57600</option>
                <option value="115200">115200</option>
            </select>
            <button id="start-udp-btn" onclick="startUdpToSerial()">启动UDP转串口</button>
            <button id="stop-udp-btn" onclick="stopUdpToSerial()">停止UDP转串口</button>
            <span id="udp-status" class="udp-status-indicator udp-status-off"></span>
        </div>
        <div class="udp-terminal" id="udp-terminal"></div>
    </div>

    <script>
        let pollingInterval;
        let pollingFailures = 0;
        const endlines = ["", "\\r", "\\n", "\\r\\n"];
        let udpPollingInterval;

        function loadSerialPorts() {
            fetch('/scan_serial_ports')
                .then(response => response.json())
                .then(ports => {
                    const serialPortsSelect = document.getElementById('serial-ports');
                    const udpSerialPortsSelect = document.getElementById('udp-serial-port');
                    serialPortsSelect.innerHTML = '<option value="">选择串口设备</option>';
                    udpSerialPortsSelect.innerHTML = '<option value="">选择串口设备</option>';
                    ports.forEach(port => {
                        const option1 = document.createElement('option');
                        option1.value = port;
                        option1.textContent = port;
                        serialPortsSelect.appendChild(option1);

                        const option2 = document.createElement('option');
                        option2.value = port;
                        option2.textContent = port;
                        udpSerialPortsSelect.appendChild(option2);
                    });
                    loadLastSettings();
                })
                .catch(error => console.error('扫描串口设备时出错:', error));
        }

        function loadLastSettings() {
            fetch('/get_last_settings')
                .then(response => response.json())
                .then(settings => {
                    if (settings.last_port) {
                        document.getElementById('serial-ports').value = settings.last_port;
                    }
                    if (settings.last_baud_rate) {
                        document.getElementById('baud-rate').value = settings.last_baud_rate;
                    }
                    if (settings.last_newline) {
                        document.getElementById('append-newline').value = settings.last_newline;
                    }
                    if (settings.udp_port) {
                        document.getElementById('udp-port').value = settings.udp_port;
                    }
                    if (settings.udp_serial_port) {
                        document.getElementById('udp-serial-port').value = settings.udp_serial_port;
                    }
                    if (settings.udp_baud_rate) {
                        document.getElementById('udp-baud-rate').value = settings.udp_baud_rate;
                    }
                })
                .catch(error => console.error('加载上次设置时出错:', error));
        }

        function openSerialPort() {
            const port = document.getElementById('serial-ports').value;
            const baudRate = document.getElementById('baud-rate').value;
            if (!port) {
                alert('请选择串口设备');
                return;
            }
            fetch('/open_serial_port', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ port, baudRate })
            })
                .then(response => response.json())
                .then(result => {
                    if (result.status === 'success') {
                        appendToTerminal(`串口 ${port} 已打开`);
                        updateSerialStatus(true);
                        startPolling();
                        disableUdpControls(true);
                    } else {
                        alert('打开串口失败');
                    }
                })
                .catch(error => console.error('打开串口时出错:', error));
        }

        function closeSerialPort() {
            fetch('/close_serial_port', { method: 'POST' })
                .then(response => response.json())
                .then(result => {
                    if (result.status === 'success') {
                        appendToTerminal('串口已关闭');
                        updateSerialStatus(false);
                        stopPolling();
                        disableUdpControls(false);
                    } else {
                        alert('关闭串口失败');
                    }
                })
                .catch(error => console.error('关闭串口时出错:', error));
        }

        function sendData() {
            const port = document.getElementById('serial-ports').value;
            const baudRate = document.getElementById('baud-rate').value;
            let data = document.getElementById('send-data').value;
            const newline = document.getElementById('append-newline').value;
            if (!port || !data) {
                alert('请选择串口设备并输入要发送的数据');
                return;
            }
            fetch('/send_data', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ port, baudRate, data, newline })
            })
                .then(response => response.json())
                .then(result => {
                    if (result.status === 'success') {
                        appendToTerminal(`发送: ${data}${endlines[newline]}`);
                        document.getElementById('send-data').value = ''; // 发送后清空发送框
                    } else {
                        alert('发送数据失败');
                    }
                })
                .catch(error => console.error('发送数据时出错:', error));
        }

        function appendToTerminal(message) {
            const terminal = document.getElementById('terminal');
            terminal.textContent += message + '\n';
            terminal.scrollTop = terminal.scrollHeight;
        }

        function clearTerminal() {
            document.getElementById('terminal').textContent = '';
        }

        function startPolling() {
            pollingFailures = 0;
            pollingInterval = setInterval(fetchSerialData, 1000); // 每秒1次
        }

        function stopPolling() {
            clearInterval(pollingInterval);
        }

        function fetchSerialData() {
            fetch('/read_serial_data')
                .then(response => response.json())
                .then(data => {
                    if (data.status === 'success' && data.data) {
                        appendToTerminal(`接收: ${data.data}`);
                        pollingFailures = 0; // 重置失败计数
                    }
                })
                .catch(error => {
                    console.error('读取串口数据时出错:', error);
                    pollingFailures++;
                    if (pollingFailures >= 2) {
                        stopPolling();
                        updateSerialStatus(false);
                        alert('服务端无法连接');
                    }
                });
        }

        function updateSerialStatus(isOn) {
            const statusIndicator = document.getElementById('serial-status');
            if (isOn) {
                statusIndicator.classList.remove('status-off');
                statusIndicator.classList.add('status-on');
            } else {
                statusIndicator.classList.remove('status-on');
                statusIndicator.classList.add('status-off');
            }
        }

        function startUdpToSerial() {
            const udpPort = document.getElementById('udp-port').value;
            const serialPort = document.getElementById('udp-serial-port').value;
            const baudRate = document.getElementById('udp-baud-rate').value;
            if (!udpPort || !serialPort || !baudRate) {
                alert('请填写所有UDP转串口参数');
                return;
            }
            fetch('/start_udp_to_serial', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ udpPort, serialPort, baudRate })
            })
                .then(response => response.json())
                .then(result => {
                    if (result.status === 'success') {
                        alert('UDP转串口已启动');
                        disableSerialControls(true);
                        disableUdpControls(true, false);
                        startUdpPolling();
                        updateUdpStatus(true);
                    } else {
                        alert('启动UDP转串口失败');
                    }
                })
                .catch(error => console.error('启动UDP转串口时出错:', error));
        }

        function stopUdpToSerial() {
            fetch('/stop_udp_to_serial', { method: 'POST' })
                .then(response => response.json())
                .then(result => {
                    if (result.status === 'success') {
                        alert('UDP转串口已停止');
                        disableSerialControls(false);
                        disableUdpControls(false, true);
                        stopUdpPolling();
                        updateUdpStatus(false);
                    } else {
                        alert('停止UDP转串口失败');
                    }
                })
                .catch(error => console.error('停止UDP转串口时出错:', error));
        }

        function disableSerialControls(disable) {
            document.getElementById('serial-ports').disabled = disable;
            document.getElementById('baud-rate').disabled = disable;
            document.getElementById('send-data').disabled = disable;
            document.getElementById('append-newline').disabled = disable;
            document.querySelectorAll('.controls button').forEach(button => {
                button.disabled = disable;
            });
        }

        function disableUdpControls(disableStart, disableStop) {
            document.getElementById('udp-port').disabled = disableStart;
            document.getElementById('udp-serial-port').disabled = disableStart;
            document.getElementById('udp-baud-rate').disabled = disableStart;
            document.getElementById('start-udp-btn').disabled = disableStart;
            document.getElementById('stop-udp-btn').disabled = disableStop;
        }

        function startUdpPolling() {
            udpPollingInterval = setInterval(fetchUdpStatus, 1000); // 每秒1次
        }

        function stopUdpPolling() {
            clearInterval(udpPollingInterval);
        }

        function fetchUdpStatus() {
            fetch('/get_udp_status')
                .then(response => response.json())
                .then(data => {
                    if (data.status === 'success' && data.message) {
                        appendToUdpTerminal(data.message);
                    }
                })
                .catch(error => console.error('获取UDP状态时出错:', error));
        }

        function appendToUdpTerminal(message) {
            const udpTerminal = document.getElementById('udp-terminal');
            udpTerminal.textContent += message + '\n';
            udpTerminal.scrollTop = udpTerminal.scrollHeight;
        }

        function updateUdpStatus(isOn) {
            const statusIndicator = document.getElementById('udp-status');
            if (isOn) {
                statusIndicator.classList.remove('udp-status-off');
                statusIndicator.classList.add('udp-status-on');
            } else {
                statusIndicator.classList.remove('udp-status-on');
                statusIndicator.classList.add('udp-status-off');
            }
        }

        window.onload = function () {
            loadSerialPorts();
        };
    </script>
</body>
</html>
